﻿using EFCore.BulkExtensions;
using Microsoft.EntityFrameworkCore;
using Mysoft.Common.Enum;
using Mysoft.Common.Extensions;
using Mysoft.Common.Response;
using Mysoft.Data.DBContext;
using Mysoft.Data.UserManager;
using Mysoft.Entity.Basic;
using ShardingCore.Extensions;
using System.Linq.Expressions;

namespace Mysoft.Data.Repository
{
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : EntityBase
    {
        /// <summary>
        /// EF DBContext
        /// </summary>
        EfDbContext _DbContext { get; }
        public Repository(EfDbContext DbContext)
        {
            this._DbContext = DbContext ?? throw new Exception("DbContext未实例化。");
        }
        /// <summary>
        /// 实体实例
        /// </summary>
        DbSet<TEntity> repository
        {
            get { return _DbContext.Set<TEntity>(); }
        }

        /// <summary>
        /// 系统字段,自动填写
        /// </summary>
        /// <param name="entities"></param>
        private void AddDefaultField(TEntity entities) 
        {
           
            if (UserContext.Current.UserId.HasValue)
            {
                if (!entities.CreateGuid.HasValue || entities.CreateGuid == Guid.Empty)
                {
                    entities.CreateGuid = UserContext.Current.UserInfo.Id;
                }
                if (string.IsNullOrWhiteSpace(entities.CreateName))
                {
                    entities.CreateName = UserContext.Current.UserInfo.Name;
                }
                if (!entities.UpdateGuid.HasValue || entities.UpdateGuid == Guid.Empty)
                {
                    entities.UpdateGuid = UserContext.Current.UserInfo.Id;
                }
                if (string.IsNullOrWhiteSpace(entities.UpdateName))
                {
                    entities.UpdateName = UserContext.Current.UserInfo.Name;
                }
            }
            if (!entities.CreateDate.HasValue)
            {
                entities.CreateDate = DateTime.Now;
            }
            if (!entities.UpdateDate.HasValue)
            {
                entities.UpdateDate = DateTime.Now;
            }
        }
        /// <summary>
        /// 系统字段,自动填写
        /// </summary>
        /// <param name="entities"></param>
        private void ModifyDefaultField(TEntity entities)
        {
            if (UserContext.Current.UserId.HasValue)
            {
                entities.UpdateGuid = UserContext.Current.UserInfo.Id;
                entities.UpdateName = UserContext.Current.UserInfo.Name;
            }
            entities.UpdateDate = DateTime.Now;
        }

        #region dbcontext同步
        /// <summary>
        /// 添加一个对象
        /// </summary>
        /// <param name="entities"></param>
        public virtual TEntity Add(TEntity entities)
        {
            if (entities != null)
            {
                AddDefaultField(entities);
                repository.Add(entities);
                this.Commit();
            }
            return entities;
        }
        /// <summary>
        /// 添加多个对象
        /// </summary>
        /// <param name="entities"></param>
        public virtual void AddRange(IEnumerable<TEntity> entities)
        {
            if (entities != null)
            {
                foreach (TEntity entity in entities) 
                {
                    AddDefaultField(entity);
                }
                repository.AddRange(entities);
                this.Commit();
            }
        }
        /// <summary>
        /// 删除一个对象
        /// </summary>
        /// <param name="entities"></param>
        public virtual void Delete(TEntity entities)
        {
            if (entities != null)
            {
                repository.Remove(entities);
                this.Commit();
            }
        }
        /// <summary>
        /// 删除多个对象
        /// </summary>
        /// <param name="entities"></param>
        public virtual void Delete(IEnumerable<TEntity> entities)
        {
            if (entities != null)
            {
                repository.RemoveRange(entities);
                this.Commit();
            }
        }
        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <param name="predicate"></param>
        public virtual void Delete(Expression<Func<TEntity, bool>> predicate)
        {
            List<TEntity> entities = repository.Where(predicate).ToList();
            entities.ForEach(entity =>
            {
                _DbContext.Entry<TEntity>(entity).State = EntityState.Deleted;
            });
            this.Commit();
        }


        /// <summary>
        /// 修改一个对象
        /// </summary>
        /// <param name="entities"></param>
        public virtual void Modify(TEntity entities)
        {
            if (entities != null)
            {
                 ModifyDefaultField(entities);
                _DbContext.Entry<TEntity>(entities).State = EntityState.Modified;
                 this.Commit();
            }
        }

        /// <summary>
        /// 获取一个对象
        /// </summary>
        /// <param name="id">Id</param>
        /// <returns>对象实例</returns>
        public virtual TEntity? FindFirst(Guid id)
        {
            return repository.Find(id);
        }



        /// <summary>
        /// 根据条件获取
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual TEntity? FindFirst(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.Where(predicate).FirstOrDefault();
        }
        /// <summary>
        /// 根据条件获取
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual List<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.Where(predicate).ToList();
        }
        /// <summary>
        /// AsNoTracking
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> FindAsNoTracking(Expression<Func<TEntity, bool>> predicate)
        {
            return AsNoTrackingWithIdentityResolution(predicate);
        }
        /// <summary>
        /// 不跟踪查询
        /// LINQ查询。如果修改了实体实例，则不会检测到
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<TEntity> AsNoTrackingWithIdentityResolution(Expression<Func<TEntity, bool>> predicate) 
        {
            return repository.AsNoTrackingWithIdentityResolution().Where(predicate);
        }

        /// <summary>
        ///判断是否存在
        /// </summary>
        /// <returns></returns>
        public bool Any(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.Any(predicate);
        }

        /// <summary>
        /// 分页排序
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pagesize"></param>
        /// <param name="rowcount"></param>
        /// <param name="orderBy"></param>
        /// <returns></returns>
        public IQueryable<TEntity> IQueryablePage(Expression<Func<TEntity, bool>> predicate, int pageIndex, int pagesize, out int rowcount, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true)
        {
            var queryable = FindAsNoTracking(predicate);
            pageIndex = pageIndex <= 0 ? 1 : pageIndex;
            pagesize = pagesize <= 0 ? 10 : pagesize;
            rowcount = returnRowCount ? queryable.Count() : 0;
            return queryable.GetIQueryableOrderBy<TEntity>(orderBy)
                .Skip((pageIndex - 1) * pagesize)
                .Take(pagesize);
        }
        /// <summary>
        /// 根据表达式返回IQueryable 
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> FindAsIQueryable(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.Where(predicate);
        }
       
        #endregion


        #region dbcontext 异步
        /// <summary>
        /// 异步添加一个对象
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> AddAsync(TEntity entities)
        {
            AddDefaultField(entities);
            await repository.AddRangeAsync(entities);
            await this.CommitAsync();
            return await Task.FromResult(entities);
        }
        /// <summary>
        /// 异步添加多个
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public virtual async Task AddRangeAsync(IEnumerable<TEntity> entities)
        {
            foreach (var entitie in entities)
            {
                AddDefaultField(entitie);
            }
            await repository.AddRangeAsync(entities);
            await this.CommitAsync();
        }

        /// <summary>
        /// AsNoTracking
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> FindAsNoTrackingAsync(Expression<Func<TEntity, bool>> predicate) 
        {
            return await AsNoTrackingWithIdentityResolution(predicate).ToListAsync();
        }
        /// <summary>
        /// 根据条件异步获取单个对象
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual Task<TEntity?> FindAsyncFirst(Expression<Func<TEntity, bool>> predicate)
        {
            return FindAsIQueryable(predicate).FirstOrDefaultAsync();
        }
        /// <summary>
        /// 根据条件异步获取集合
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return FindAsIQueryable(predicate).ToListAsync();
        }

        #endregion

        #region bulk


        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="entities"></param>
        public virtual void BulkAddRange(IList<TEntity> entities) 
        {
            foreach (var entitie in entities)
            {
                AddDefaultField(entitie);
            }
            _DbContext.BulkInsert(entities);
            this.Commit();
        }
        /// <summary>
        /// 异步批量新增
        /// </summary>
        /// <param name="entities"></param>
        public virtual async Task BulkAddRangeAsync(IList<TEntity> entities)
        {
            foreach (var entitie in entities)
            {
                AddDefaultField(entitie);
            }
            await _DbContext.BulkInsertAsync(entities);
            await this.CommitAsync();
        }
        /// <summary>
        /// 批量修改
        /// </summary>
        /// <param name="entities">需要传入完整实体,不传的字段就会被更新为空</param>
        public virtual void BulkUpdate(IList<TEntity> entities)
        {
            foreach (var entitie in entities)
            {
                ModifyDefaultField(entitie);
            }
            _DbContext.BulkUpdate(entities);
            this.Commit();
        }
        /// <summary>
        /// 异步批量修改
        /// </summary>
        /// <param name="entities">需要传入完整实体,不传的字段就会被更新为空</param>
        public virtual async Task BulkUpdateAsync(IList<TEntity> entities)
        {
            foreach (var entitie in entities)
            {
                ModifyDefaultField(entitie);
            }
            await _DbContext.BulkUpdateAsync(entities);
            await this.CommitAsync();
        }
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="entities"></param>
        public virtual void BulkDelete(IList<TEntity> entities) {

            _DbContext.BulkDelete(entities);
            this.Commit();
        }
        /// <summary>
        /// 异步批量删除
        /// </summary>
        /// <param name="entities"></param>
        public virtual async Task BulkDeleteAsync(IList<TEntity> entities)
        {

            await _DbContext.BulkDeleteAsync(entities);
            await this.CommitAsync();
        }
        #endregion

        /// <summary>
        /// 提交
        /// </summary>
        public int Commit()
        {
            return _DbContext.SaveChanges();
        }
        /// <summary>
        /// 异步提交
        /// </summary>
        public async Task<int> CommitAsync()
        {
            return await _DbContext.SaveChangesAsync();
        }

        #region 事务
        public ResponseContent BeginTransaction(Func<ResponseContent> func, System.Data.IsolationLevel IsolationLevel = System.Data.IsolationLevel.ReadUncommitted) {
            var result = new ResponseContent();
            using (var dbContextTransaction = _DbContext.Database.BeginTransaction(IsolationLevel))
            {
                try
                {
                    func.Invoke();
                    dbContextTransaction.Commit();
                    result.code = 200;
                    return result;
                }
                catch (Exception e)
                {
                    dbContextTransaction.Rollback();
                    result.code = 500;
                    result.message = e.Message;
                    return result;
                }
            }
        }

        #endregion
    }
}
